"""
重载Rule与Blueprint类使支持角色权限控制，同时提供代码提示
"""
from typing import Union
from uuid import uuid1

from flask import blueprints
from werkzeug.routing import Rule

from app.role_control import (
    BaseBlueControl,
    BaseRuleControl,
    ControlType,
    DefaultBlueprintControl,
    DefaultRuleControl,
)
from configs.settings import RULE_WHITE_LIST

# 支持的请求方法
SUPPORT_METHOD = ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS", "HEAD"]


class ExtBlueprint(blueprints.Blueprint):
    """Blueprint重载 支持角色权限控制粗度到模块级别

    :param role_control Union[BaseBlueControl]:
        - BaseRuleControl子类：默认为 app.role_control.DefaultBlueprintControl 仅允许教师访问
    """

    def __init__(self, *args, **kwargs):

        _control = kwargs.pop("role_control", DefaultBlueprintControl)
        if not issubclass(_control, BaseBlueControl):
            raise AttributeError(
                f"蓝图中 role_control 参数必须是 BaseBlueControl 的子类，而不是: {_control}"
            )
        if _control.control_type != ControlType.blueprint:
            raise AttributeError(f"{_control}的`control_type`应该是`ControlType.blueprint`")

        self.role_control = _control()
        if not self.role_control.title:
            self.role_control.title = kwargs.get("name", "")

        super().__init__(*args, **kwargs)

        # 注册路由生成偏函数时，蓝图还未被添加到app.blueprints中，对应name还未生成（在app注册蓝图时生成）所以通过uuid预标记蓝图
        # 动态生成即可，不需要保存
        # 性能：10000次调用耗时0.07秒
        self.uuid = int(uuid1())
        # 蓝图最后保存在app蓝图字典中真实key名称
        self.real_name = self.name

    def register(self, app, options):
        res = super().register(app, options)
        self.real_name = (
            f'{options.get("name_prefix", "")}.{options.get("name", self.name)}'.lstrip(
                "."
            )
        )
        return res

    def route(self, rule, **options):
        """保证route方式添加的路由正常使用"""

        def decorator(f):
            endpoint = options.pop("endpoint", None)
            options.update({"parent_blueprint_uuid": self.uuid})
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator


class ExtRule(Rule):
    """Rule重载 支持角色权限控制细度到按钮级别，兼容多路由和多种请求方法绑定

    基本描述参数：
    :param role_control Union[False, BaseRuleControl]:
        - False: 不受权限控制，属于白名单授权
        - BaseRuleControl子类：默认为 app.role_control.DefaultRuleControl 仅允许教师访问
    """

    def __init__(self, *args, **kwargs):

        self.parent_blueprint_uuid: Union[int, None] = kwargs.pop(
            "parent_blueprint_uuid", None
        )

        _control = kwargs.pop("role_control", DefaultRuleControl)
        if _control is not False:
            if not issubclass(_control, BaseRuleControl):
                raise AttributeError(
                    f"Rule 中 role_control 参数必须是 BaseRuleControl 的子类，而不是: {_control}"
                )
            if _control.control_type != ControlType.rule:
                raise AttributeError(f"{_control}的`control_type`应该是`ControlType.rule`")

            self.role_control = _control()
            if not self.role_control.title:
                self.role_control.title = kwargs.get("endpoint", "")
        else:
            self.role_control = _control

        add_global_white_list = False

        if self.role_control is False:
            add_global_white_list = True
            self.sub_control = False

        super().__init__(*args, **kwargs)

        if add_global_white_list:
            RULE_WHITE_LIST.add(self.rule)
